#include "object_co_bytes.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// #include "util/hex_util.h"

#define printf(fmt, ...) //fprintf(stdout, fmt, ##__VA_ARGS__)

// 是否转换网络字节序
static int is_co_network_byte_order(int type, int size) {
    int num = 0x12345678;
    if (*(char *)&num == 0x78) { // 小端
        return 0;
    }
    if (type == E_OFT_INT16   && type == E_OFT_UINT16 && 
        type == E_OFT_INT32   && type == E_OFT_UINT32 &&
        type == E_OFT_INT64   && type == E_OFT_UINT64 &&
        type == E_OFT_FLOAT32 && type == E_OFT_FLOAT64
    ) {
        return 1;   
    }
    return 0;
}
// 转换网络字节序
static int co_network_byte_order(int type, int size, uint8_t *src, uint8_t *dst) {
    if (is_co_network_byte_order(type, size)) {
        for (int i=0;i<size;i++) {
            dst[i] = src[size-1-i];
        }
        return size;
    }
    memcpy(dst, src, size);
    return size;
}

// 转换主机字节序
static int co_host_byte_order(int type, int size, uint8_t *src, uint8_t *dst) {
    return co_network_byte_order(type, size, src, dst);
}

static int hton_num(int num_size, uint8_t *src, uint8_t *dst) {
    int num = 0x12345678;
    if (*(char *)&num == 0x78) {
        memcpy(dst, src, num_size);
    } else {
        for (int i=0;i<num_size;i++) {
            dst[i] = src[num_size-1-i];
        }
    }
    return num_size;
}

static int ntoh_num(int num_size, uint8_t *src, uint8_t *dst) {
    return hton_num(num_size, src, dst);
}

static int get_string_co_binary_size(int field_type, uint64_t field_size, uint8_t *src, uint64_t src_size) {
    uint64_t len = strlen((char*)src);
    if (len > field_size) {
        len = field_size;
    }
    if (len > src_size){
        return -1;
    }
    int num_size = 8;
    if (field_size <= 255) {
        num_size = 1;

    }else if (field_size <= 65535) {
        num_size = 2;
    } else if (field_size <= 4294967295) {
        num_size = 4;
    } 
    return len + num_size;
}

static int string_co_binary(int field_type, uint64_t field_size, uint8_t *src, uint64_t src_size, uint8_t *dst, uint64_t dst_size) {
    uint64_t len = strlen((char*)src);
    if (len > field_size) {
        len = field_size;
    }
    if (len > src_size){
        return -1;
    }
    if (dst_size < len){
        return -1;
    }
    int num_size = 8;
    if (field_size <= 255) {
        num_size = 1;
        if (dst_size < len+num_size){
            return -1;
        }
        uint8_t tmp = len;
        hton_num(num_size, &tmp, dst);

    }else if (field_size <= 65535) {
        num_size = 2;
        if (dst_size < len+num_size){
            return -1;
        }
        uint16_t tmp = len;
        hton_num(num_size, (uint8_t*)&tmp, dst);
    } else if (field_size <= 4294967295) {
        num_size = 4;
        if (dst_size < len+num_size){
            return -1;
        }
        uint32_t tmp = len;
        hton_num(num_size, (uint8_t*)&tmp, dst);
    } else {
        hton_num(num_size, (uint8_t*)&len, dst);
    }
    memcpy(dst + num_size, src, len);
    return len + num_size;
}

static int binary_co_string(int field_type, uint64_t field_size, uint8_t *src, uint64_t src_size, uint8_t *dst, uint64_t dst_size) {
    uint64_t len = 0;
    int num_size = 8;
    if (field_size <= 255) {
        num_size = 1;
        if (src_size < num_size)
        {
            return -1;
        }
        uint8_t tmp = 0;
        hton_num(num_size, src, &tmp);
        len = tmp;
    }else if (field_size <= 65535) {
        num_size = 2;
        if (src_size < num_size)
        {
            return -1;
        }
        uint16_t tmp = 0;
        hton_num(num_size, src, (uint8_t*)&tmp);
        len = tmp;
    } else if (field_size <= 4294967295) {
        num_size = 4;
        if (src_size < num_size)
        {
            return -1;
        }
        uint32_t tmp = 0;
        hton_num(num_size, src, (uint8_t*)&tmp);
        len = tmp;
    } else {
        if (src_size < num_size)
        {
            return -1;
        }
        hton_num(num_size, src, (uint8_t*)&len);
    }
    if (src_size < num_size+len)
    {
        return -2;
    }
    if (dst_size < len)
    {
        return -3;
    }
    memcpy(dst, src+num_size, len);
    return len + num_size;
}
// 对象结构转字节串
int object_co_bytes (const char *name, void *obj, void *obj_desc_ptr, int32_t obj_field_count, uint8_t *buf, uint64_t buf_size, int depth)
{
    printf("%s:%d name=%s obj_field_count=%d st_obj_desc_t=%lu depth = %d\n", __func__, __LINE__, name, obj_field_count,  sizeof(st_obj_desc_t), depth);
    int ret = 0;
    int pos = 0;
    for (int i=0;i<obj_field_count;i++)
    {
        st_obj_desc_t *info = obj_desc_ptr+i*(sizeof(st_obj_desc_t));
        void *ptr = obj+ info->offset;
        printf("%s:%d name=%s info->offset=%u info->size=%llu\n", __func__, __LINE__, info->name, info->offset, info->size);
        if (info->type >= E_OFT_END || info->type  <= E_OFT_NONE)
        {
            return -1*pos;
        }
        if (info->type == E_OFT_ARR_HEAP || info->type == E_OFT_ARR_STACK)
        {
            int count = 0;
            if (info->type == E_OFT_ARR_STACK) {
                if (info->msize == 0) {
                    return -1*pos;
                }
                count = info->size / info->msize;
            }
            else {
                for (int j=0;j<obj_field_count;j++) {
                    st_obj_desc_t *sub_info = obj_desc_ptr+j*(sizeof(st_obj_desc_t));
                    if (info->noffset == sub_info->offset) {

                        if (sub_info->size == 1) {
                            count = *(uint8_t*)(obj + sub_info->offset);
                        } else if (sub_info->size == 2) {
                            count = *(uint16_t*)(obj + sub_info->offset);
                        } else if (sub_info->size == 4) {
                            count = *(uint32_t*)(obj + sub_info->offset);
                        } else if (sub_info->size == 8) {
                            count = *(uint64_t*)(obj + sub_info->offset);
                        }
                        break;
                    }
                    sub_info = NULL;
                }
            }
            if (count == 0) {
                printf("%s:%d name=%s not found info->noffset=%d\n", __func__, __LINE__, info->name, info->noffset);
                continue;
            }
            if (info->type == E_OFT_ARR_HEAP && ((*(void **)ptr)) == NULL) {
                return -1*pos;
            }
            printf("%s:%d name=%s count=%d\n", __func__, __LINE__, info->name, count);
            for (int j=0;j<count;j++) {
                void *sub_obj = ((*(void **)ptr)) + j * info->msize;
                if (info->type == E_OFT_ARR_STACK) {
                    sub_obj = ptr + j * info->msize;
                }
                if (info->mtype == E_OFT_STRUCT) {
                    ret = object_co_bytes(info->name, sub_obj, info->info_ptr, info->info_field_size, buf + pos, buf_size-pos, depth*10);
                    if (ret < 0) {
                        return -1*pos + ret;
                    }
                    pos += ret;
                }
                // else if (info->mtype == E_OFT_STRING)  // 不会出现
                // {
                //     ret = string_co_binary(info->mtype, info->msize, sub_obj, info->msize, buf+pos, buf_size-pos);
                //     if (ret < 0) {
                //         return -1*pos;
                //     }
                //     pos += ret;
                // }
                else {
                    co_network_byte_order(info->mtype, info->msize, sub_obj, (uint8_t *)(buf + pos));
                    pos += info->msize;
                }
            }
        }
        else if (info->type == E_OFT_STRUCT)
        {
            ret = object_co_bytes(info->name, obj + info->offset, info->info_ptr, info->info_field_size, buf+pos, buf_size, depth*10);  
            if (ret < 0) {
                return -1*pos + ret;
            }
            pos += ret;
        }
        else if (info->type == E_OFT_STRING)
        {
            ret = string_co_binary(info->type, info->size, ptr, info->size, buf+pos, buf_size-pos);
            if (ret < 0) {
                return -1*pos;
            }
            pos += ret;
        }
        else
        {
            co_network_byte_order(info->type, info->size, ptr, (uint8_t *)(buf + pos));
            pos += info->size;
        }
    }
    return pos;
}
// 字节转对象结构
int bytes_co_object (const char *name, uint8_t *buf, uint64_t buf_size, void *obj, void *obj_desc_ptr, int32_t obj_field_count,  int depth) {
    int pos = 0;
    int ret = 0;
    // char hex[1024] = { 0x00 };
    for (int i=0;i<obj_field_count;i++)
    {
        st_obj_desc_t *info = obj_desc_ptr+i*(sizeof(st_obj_desc_t));
        void *ptr = obj+ info->offset;
        // uint32_t hex_len = 1024;
        // encode_hex(buf+pos, buf_size-pos, hex, &hex_len, 0);
        // printf("%s:%d name=%s info->offset=%u info->size=%llu len=%llu hex=%s\n", __func__, __LINE__, info->name, info->offset, info->size, buf_size-pos, hex);

        if (info->type >= E_OFT_END || info->type <= E_OFT_NONE)
        {
            return -1*pos;
        }
        if (info->type == E_OFT_ARR_HEAP || info->type == E_OFT_ARR_STACK)
        {
            int count = 0;
            if (info->type == E_OFT_ARR_STACK) {
                if (info->msize == 0) {
                    return -1*pos;
                }
                count = info->size / info->msize;
            }
            else {
                for (int j=0;j<obj_field_count;j++) {
                    st_obj_desc_t *sub_info = obj_desc_ptr+j*(sizeof(st_obj_desc_t));
                    if (info->noffset == sub_info->offset) {
                        if (sub_info->size == 1) {
                            count = *(uint8_t*)(obj + sub_info->offset);
                        } else if (sub_info->size == 2) {
                            count = *(uint16_t*)(obj + sub_info->offset);
                        } else if (sub_info->size == 4) {
                            count = *(uint32_t*)(obj + sub_info->offset);
                        } else if (sub_info->size == 8) {
                            count = *(uint64_t*)(obj + sub_info->offset);
                        }
                        break;  
                    }
                }
            }
            if (count == 0) {
                printf("%s:%d name=%s not found info->noffset=%d\n", __func__, __LINE__, info->name, info->noffset);
                continue;
            }
            printf("%s:%d name=%s count=%d pos=%d\n", __func__, __LINE__, info->name, count, pos);
            if (info->type == E_OFT_ARR_HEAP) {
                *(void **)ptr = malloc(count * info->msize);
                memset(*(void **)ptr, 0, count * info->msize);
            }
            for (int j=0;j<count;j++) {
                printf("%s:%d name=%s count=%d pos=%d j=%d\n", __func__, __LINE__, info->name, count, pos, j);
                void *sub_obj = ((*(void **)ptr)) + j * info->msize;
                if (info->type == E_OFT_ARR_STACK) {
                    sub_obj = ptr + j * info->msize;
                }
                if (info->mtype == E_OFT_STRUCT) {
                    ret = bytes_co_object(info->name, buf+pos, buf_size-pos, sub_obj, info->info_ptr, info->info_field_size, depth*10);
                    if (ret < 0) {
                        return -1*pos;
                    }
                    pos += ret;
                } else {
                    memcpy(sub_obj, buf + pos, info->msize);
                    pos += info->msize;
                }
            }
        } else if (info->type == E_OFT_STRUCT)
        {
            ret = bytes_co_object(info->name, buf+pos, buf_size-pos, obj + info->offset, info->info_ptr, info->info_field_size,  depth*10);  
            if (ret < 0) {
                return -1*pos;
            }
            pos += ret;
        }
        else if (info->type == E_OFT_STRING)
        {
            ret = binary_co_string(info->type, info->size, buf+pos, buf_size-pos, ptr, info->size);
            if (ret < 0) {
                return -1*pos;
            }
            pos += ret;
        }
        else
        {
            memcpy(ptr, buf + pos, info->size);
            pos += info->size;
        }
    }
    return pos;
}


// 获取字节数组长度
int get_object_co_bytes_size(const char *name, void *obj, void *obj_desc_ptr, int32_t obj_field_count) {
    printf("%s:%d name=%s obj_field_count=%d st_obj_desc_t=%lu\n", __func__, __LINE__, name, obj_field_count,  sizeof(st_obj_desc_t));
    int ret = 0;
    int pos = 0;
    for (int i=0;i<obj_field_count;i++)
    {
        st_obj_desc_t *info = obj_desc_ptr+i*(sizeof(st_obj_desc_t));
        void *ptr = obj+ info->offset;
        printf("%s:%d name=%s info->offset=%u info->size=%llu\n", __func__, __LINE__, info->name, info->offset, info->size);
        if (info->type == E_OFT_END)
        {
            break;
        }
        if (info->type == E_OFT_ARR_HEAP || info->type == E_OFT_ARR_STACK)
        {
            int count = 0;
            for (int j=0;j<obj_field_count;j++) {
                st_obj_desc_t *sub_info = obj_desc_ptr+j*(sizeof(st_obj_desc_t));
                if (info->noffset == sub_info->offset) {

                    if (sub_info->size == 1) {
                        count = *(uint8_t*)(obj + sub_info->offset);
                    } else if (sub_info->size == 2) {
                        count = *(uint16_t*)(obj + sub_info->offset);
                    } else if (sub_info->size == 4) {
                        count = *(uint32_t*)(obj + sub_info->offset);
                    } else if (sub_info->size == 8) {
                        count = *(uint64_t*)(obj + sub_info->offset);
                    }
                    break;
                }
                sub_info = NULL;
            }
            if (count == 0) {
                printf("%s:%d name=%s not found info->noffset=%d\n", __func__, __LINE__, info->name, info->noffset);
                return 0;
            }
            if (info->type == E_OFT_ARR_HEAP && ((*(void **)ptr)) == NULL) {
                return -1;
            }

            printf("%s:%d name=%s count=%d\n", __func__, __LINE__, info->name, count);
            for (int j=0;j<count;j++) {
                void *sub_obj = ((*(void **)ptr)) + j * info->msize;
                if (info->type == E_OFT_ARR_STACK) {
                    sub_obj = ptr + j * info->msize;
                }
                if (info->mtype == E_OFT_STRUCT) {
                    ret = get_object_co_bytes_size(info->name, sub_obj, info->info_ptr, info->info_field_size);
                    if (ret < 0) {
                        return -1*pos;
                    }
                    pos += ret;
                }
                else {
                    pos += info->msize;
                }
            }
        }
        else if (info->type == E_OFT_STRUCT)
        {
            ret = get_object_co_bytes_size(info->name, obj + info->offset, info->info_ptr, info->info_field_size);  
            if (ret < 0) {
                return -1*pos;
            }
            pos += ret;
        }
        else if (info->type == E_OFT_STRING)
        {
            ret = get_string_co_binary_size(info->type, info->size, ptr, info->size);
            if (ret < 0) {
                return -1*pos;
            }
            pos += ret;
        }
        else
        {
            pos += info->size;
        }
    }
    return pos;
}